#!/usr/bin/env python3
# -*- coding:utf-8 -*-

import os
import sys
import subprocess
from typing import Iterable

from ctools.converters.conv_sn import ConvSN2Gv
from ctools.ly_parser.nodes import CTreeNode
from ctools.datahelper.texthelper import TreeTextParser

from ctools.logext import *
import logging

_rlog, _plog, _mlog, _tlog = get_loggers(__file__, __name__, propagate=False)

class CFlowHelper(object):
    def __init__(self) -> None:
        try:
            cmd = ['which', 'cflow']
            self._cflow_exe = subprocess.check_output(cmd, universal_newlines=True).strip()
            _mlog.debug(f'cflow exe: {self._cflow_exe}')
        except Exception as e:
            raise e

    def _do_cmd(self, args):
        cmd = [self._cflow_exe,
            "--level", "'0=|   '",
            "--level", "'1=|   '",
            "--level", "'end0=+-- '",
            "--level", "'end1=+-- '",
            "--omit-arguments",         # don't print argument lists in function declarations
            "--omit-symbol-names",      # don't print symbol names in declaration strings
        ]

        if isinstance(args, Iterable):
            cmd.extend(args)
        elif isinstance(args, str):
            cmd.append(args)
        else:
            _mlog.exception(f'unknown args type: {type(args)}')

        cmd.append('2> /dev/null')

        try:
            ret = subprocess.run(' '.join(cmd), shell=True, text=True, stdout=subprocess.PIPE)
            return ret.stdout
        except Exception as e:
            _mlog.exception('Error: ', e)
            raise e

    def do_calltree(self, filenames:list[str]|tuple[str],
                    funcs:list[str]|tuple[str], level=1):
        if isinstance(filenames, str):
            filenames = [filenames]
        if isinstance(funcs, str):
            funcs = [funcs]

        args = ['-d', str(level + 1),]
        args.extend([f'-m {func}' for func in funcs])
        args.extend(filenames)

        text = self._do_cmd(args)
        buf = ''
        for line in text.splitlines():
            line = line.strip()
            pos = line.find('(')
            if pos >= 0:
                line = line[:pos]
            buf += line + '\n'
        return buf

if __name__ == '__main__':
    ch = CFlowHelper()
    ret = ch.do_calltree(
            '/data/eel/source/kernel/linux-6.6/init/main.c',
            'rest_init', 2
        )
    # print(ret)
    tp = TreeTextParser()
    root = tp.do_parse_text(ret)
    root.dump()
    sn2gv = ConvSN2Gv()
    text = sn2gv.convert(root)
    print(text)
